﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using MacomberMapSystem.Common.Serialization;
using MacomberMapSystem.Common.Database;
using System.IO;
using MacomberMapSystem.Common.CIM;
using MacomberMapSystem.Common.Internals;

namespace MacomberMapSystem.Common.Processing
{
    /// <summary>
    /// (C) 2012, Michael E.  Legatt, Ph.D., Electric Reliability Council of Texas, Inc.
    /// This class provides the breaker-to-breaker trace information in an XML document, including traces, associated equipment, and connected contingencies and lines/XFs.
    /// </summary>
    public class CIM_CRRTracer : CIM_Processor
    {
        #region Variable declarations
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new CRR tracer
        /// </summary>
        /// <param name="xElem"></param>
        /// <param name="NamedParameters"></param>
        /// <param name="Repository"></param>
        public CIM_CRRTracer(XmlElement xElem, Dictionary<String, object> NamedParameters, MM_Repository Repository)
            : base(xElem, NamedParameters, Repository)
        { }
        #endregion

        /// <summary>
        /// Report the name of our process
        /// </summary>
        public override string ProcessName
        {
            get { return "CRR Tracer"; }
        }

        /// <summary>
        /// Initiate our process of tracing outward
        /// </summary>
        /// <param name="DbConn"></param>
        /// <returns></returns>
        public override CIM_Processor.enumProcessState InitiateProcess(MM_Database_Connector DbConn)
        {
            //First, build our list of elements to be processed
            MM_Database_Model Model = NamedParameters["Model"] as MM_Database_Model;
            Total = Model.Traces.Count;
            try
            {
                WriteXmlFile(ProcessString(Path.Combine(TargetFolder, TargetFileName)), Model, DbConn, ref Current, Repository);
                return enumProcessState.Completed;
            }
            catch (Exception ex)
            {
                base.ProcessLog.AppendLine("Error: " + MM_System_Interface.ConvertError(ex));
                return enumProcessState.FailedWithErrors;
            }
        }

        /// <summary>
        /// Write out our XML file
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="CurModel"></param>
        /// <param name="DbConn"></param>
        /// <param name="Current"></param>
        /// <param name="Repository"></param>
        private static void WriteXmlFile(string FileName, MM_Database_Model CurModel, MM_Database_Connector DbConn, ref float Current, MM_Repository Repository)
        {
            Current = 0;
            
            using (XmlTextWriter xW = new XmlTextWriter(FileName, new UTF8Encoding(false)))
            {
                xW.Formatting = Formatting.Indented;
                xW.WriteStartDocument();
                xW.WriteStartElement("CRR_Traces");
                foreach (CIM_Trace Trace in CurModel.Traces.Values)
                {
                    xW.WriteStartElement("Trace");
                    xW.WriteAttributeString("Name", Trace.Name);
                    xW.WriteAttributeString("Description", Trace.Description);

                    //Write out our element TEIDs, and add line/XF TEIDs within to our list
                    StringBuilder sB = new StringBuilder();
                    StringBuilder LnXf = new StringBuilder();
                    SortedDictionary<int, String> Buses = new SortedDictionary<int, string>();

                    UInt64 TEID;
                    foreach (CIM_Element Elem in Trace.Elements)
                    {
                        if (UInt64.TryParse(Elem.TEID, out TEID))
                            sB.Append((sB.Length == 0 ? "" : ",") + TEID.ToString());
                        if (Elem.TypeName == "cim:ACLineSegment" || Elem.TypeName == "cim:PowerTransformer")
                            LnXf.Append((LnXf.Length == 0 ? "" : ",") + Elem.TEID.ToString());
                        if (Elem.TypeName == "cim:ConnectivityNode")
                        {
                            CIM_Element NodeGroup = Elem.ParseSingle("etx:ConnectivityNodeGroup", Elem.CIM);
                            int PSSEBus = int.Parse(NodeGroup["etx:ConnectivityNodeGroup.PSSEBusNumber"]);
                            if (!Buses.ContainsKey(PSSEBus))
                                Buses.Add(PSSEBus, PSSEBus.ToString() + " (" + NodeGroup["etx:ConnectivityNodeGroup.PSSEBusName"] + ")");
                        }
                    }
                    xW.WriteAttributeString("TEIDs", sB.ToString());

                    //Assemble our list of connected traces, and our list of line/XF TEIDs
                    sB = new StringBuilder();
                    foreach (CIM_Trace ConnectedTrace in Trace.ConnectedTraces)
                    {
                        sB.Append((sB.Length == 0 ? "" : ",") + ConnectedTrace.Name);
                        foreach (CIM_Element Elem in ConnectedTrace.Elements)
                            if (Elem.TypeName == "cim:ACLineSegment" || Elem.TypeName == "cim:PowerTransformer")
                                LnXf.Append((LnXf.Length == 0 ? "" : ",") + Elem.TEID.ToString());
                    }

                    

                    xW.WriteAttributeString("ConnectedTraces", sB.ToString());
                    xW.WriteAttributeString("LinesAndXFs", LnXf.ToString());
                    xW.WriteAttributeString("PSSeBuses", String.Join(",", Buses.Values.ToArray()));
                    xW.WriteEndElement();
                    Current++;
                }
                xW.WriteEndElement();
            }
        }
    }
}